package controller;

/**
 * GameControl is an encapsulation of a relationship between
 * a keyboard action and a <code>Controller</code> operation.
 * 
 * @deviation
 * Changed the execute() operation to accept a char as a parameter
 * reduce TDA violation. Even though it could be deemed 'filtering' it is not
 * a bad idea to change to this new method.
 * 
 * @deviation
 * Changed the name of operation setKeyChar to setActionCode
 * 
 * @deviation
 * Changed from being based on characters to java key codes
 * to allow for more fine-grained control (function keys for example)
 * 
 * @deviation
 * Added the ability to enable/disable the GameControl through
 * setEnabled(boolean)
 * 
 * @deviation
 * Added a reassignable flag that determines whether or not
 * the GameControl is reassignable
 * 
 * @author matt
 *
 */
public abstract class GameControl {
	private int mActionCode;					// The triggering action key char
	private String mActionId;					// The action identifier (used in saving)
	private String mActionDescription;			// The action description (used for customization)
	
	private boolean mReassignable;
	private boolean mEnabled;
	
	/**
	 * Default constructor requires at least an activation
	 * character to be linked to.
	 * 
	 * @param actionChar	char		The action character.
	 */
	public GameControl(int actionCode) {
		this(actionCode, "", "");
	}
	
	/**
	 * Advanced constructor that creates a new <code>GameControl</code>
	 * bound to the <code>actionChar</code> and associated
	 * with the given <code>id.</code>
	 * 
	 * @param actionChar	char		The action character.
	 * @param id			String		The string identifier.
	 */
	public GameControl(int actionCode, String id) {
		this(actionCode, "", "");
	}
	
	/**
	 * Advanced constructor that creates a new <code>GameControl</code>
	 * bound to the <code>actionChar</code> and associated with the
	 * given <code>id</code> with description <code>desc.</code>
	 * 
	 * @param actionChar	char		The action character.
	 * @param id			String		The string identifier.
	 * @param desc			Stirng		The description string.
	 */
	public GameControl(int actionCode, String id, String desc) {
		mActionCode = actionCode;
		mActionId = id;
		mActionDescription = desc;
		
		mReassignable = true;
		mEnabled = true;
	}

	/**
	 * Executes the <code>GameControl</code> with the condition that the
	 * passed <code>keyChar</code> matches the current
	 * action character this <code>GameControl</code> is bound to.
	 * 
	 * @param keyChar		char		The key pressed by the player.
	 * @return	boolean		True iff this control should be executed again.
	 * @deviation See class notes.	
	 */
	public void execute(int keyCode) {
		if (! mEnabled) return;
		if (keyCode == mActionCode) {
			// we should execute
			this.execute();
		}
	}
	
	/**
	 * Blindly execute the command without checking
	 * for parameters first. This method is protected
	 * so that it can only be called by the
	 * execute(char) operation.
	 */
	protected abstract void execute();
	
	/**
	 * Changes the activation character to a new character
	 * specified in the parameters. The new key takes
	 * effect immediately.
	 * 
	 * @param newActionChar		char	The new action char.
	 */
	public void setActionCode(int newActionCode) {
		if (newActionCode != mActionCode) {
			System.out.format("GameControl::setActionCode() > {id=%s key=%d->%d enabled=%b}\n", this.getId(), this.getActionCode(), newActionCode, this.isEnabled());
		}
		mActionCode = newActionCode;
	}
	
	
	/**
	 * Returns the String Id of this GameControl.
	 * 
	 * @return	String		The id of this GameControl.
	 */
	public String getId() {
		return (mActionId);
	}
	
	/**
	 * Returns the String representation of the description
	 * of this <code>GameControl</code>.
	 * 
	 * @return	String		Description of this GameControl's responsibility.
	 */
	public String getDescription() {
		return (mActionDescription);
	}

	
	protected void keyReleased() {}
	
	
	/**
	 * Returns the the character this <code>GameControl</code>
	 * is currently bound to.
	 * 
	 * @return		char		The current action character.
	 */
	public int getActionCode() {
		return (mActionCode);
	}
	
	public String toString() {
		return (String.format("Control:\n\tAction=%d\n\tId=%s\n\tDescription=%s",
									getActionCode(),
									getId(),
									getDescription()));
	}
	
	
	public void setEnabled(boolean enabled) {
		if (enabled != mEnabled) {
			//System.out.format("Control state changed: {id=%s key=%d enabled=%b->%b}\n", this.getId(), this.getActionCode(), this.isEnabled(), enabled);
		}
		mEnabled = enabled;
	}
	
	public boolean isEnabled() {
		return (mEnabled);
	}
	
	public void setReassignable(boolean isReassignable) {
		mReassignable = isReassignable;
	}
	
	
	public boolean isReassignable() {
		return (mReassignable);
	}
}
